package com.zhen.process;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.map.CaseInsensitiveMap;

import com.zhen.annotation.HtmlBean;
import com.zhen.annotation.OrderPolicy;
import com.zhen.annotation.ParamBean;
import com.zhen.annotation.ProcessMethod;
import com.zhen.annotation.SpringAnnotationScanner;
import com.zhen.pojo.Columns;
import com.zhen.util.ClassUtils;
import com.zhen.util.SpringUtil;

public class BaseProcess {

	//只能在OrderPolicy.object执行顺序的方法中使用
	private Map<String, Object> currObj;
	private Object prevValue;
	private Columns currColumns;
	private List<CaseInsensitiveMap> insertList = new ArrayList<CaseInsensitiveMap>(0);
	private int currIndex;
	//存放所有待插入数据库的数据集合
	private List<CaseInsensitiveMap> allInsertList;

	//还需要继续执行
	private Boolean isAfreshExecute = false;
	private int afreshExecuteCount = 0;
	
	public static List<CaseInsensitiveMap> packInsert(int number, List<Columns> columns) throws Exception {
		List<CaseInsensitiveMap> objList = new ArrayList<CaseInsensitiveMap>();
		Map<String, Object> prevValueMap = new CaseInsensitiveMap();
		for (int x = 0; x < number; x++) {
			CaseInsensitiveMap obj = new CaseInsensitiveMap(columns.size());
			List<String> list = new ArrayList<String>();
			List<ParamBean> paramBeanList = new ArrayList<ParamBean>();
			for (Columns column : columns) {

				if(column.getProcess() == null){
					obj.put(column.getColumnName(), null);
					continue;
				}
				Class<?>[] paramTypes = null;
				Object[] param = null;
				if(column.getProcess().getHtml() != null){
					
					paramTypes = new Class<?>[column.getProcess().getHtml().size()];
					 param = new Object[column.getProcess().getHtml().size()];
					int z = 0;
					for (HtmlBean htmlbean : column.getProcess().getHtml()) {
						paramTypes[z] = ClassUtils.getBaseClass(htmlbean.getParamType());
						param[z] = ClassUtils.parsClassVal(htmlbean.getParamType(), htmlbean.getValue());
						z++;
					}
				}
				Object bean = SpringUtil.getBean("springAnnotationScanner",SpringAnnotationScanner.class).getBeanMap().get(column.getProcess().getBeanName()).getClass()
						.newInstance();
					
				Method method = bean.getClass()//
						.getMethod(column.getProcess().getMethodName(), paramTypes);

				Method method4 = bean.getClass().getMethod("setCurrIndex", int.class);
				method4.invoke(bean, (x+1));
				
				//判断实行顺序
				String type = method.getAnnotation(ProcessMethod.class).order().getType();
				if(type.equals(OrderPolicy.column.getType())){
					
					if (prevValueMap.containsKey(column.getColumnName())) {
						Method method2 = bean.getClass().getMethod("setPrevValue", Object.class);
						method2.invoke(bean, prevValueMap.get(column.getColumnName()));
					}
					if (bean instanceof ColumnProcess && "column".equals(method.getName())) {
						list.add(column.getColumnName());
					}
					Method method2 = bean.getClass().getMethod("setCurrColumns", Columns.class);
					method2.invoke(bean, column);
					
					Method method3 = bean.getClass().getMethod("setCurrObj", Map.class);
					method3.invoke(bean, obj);
					
					//执行处理器
					Object invoke = method.invoke(bean, param);
					prevValueMap.put(column.getColumnName(), invoke);
					obj.put(column.getColumnName(), invoke);
					
				}else if(type.equals(OrderPolicy.object.getType())){
					
					ParamBean paramBean = new ParamBean();
					paramBean.setBean(bean);
					paramBean.setPrevValue(prevValueMap.get(column.getColumnName()));
					paramBean.setColumn(column);
					paramBean.setMethod(method);
					paramBean.setParam(param);
					paramBeanList.add(paramBean);
				}
				
				Method method3 = bean.getClass().getMethod("getInsertList");
				List<CaseInsensitiveMap> invoke2 = (List<CaseInsensitiveMap>)method3.invoke(bean);
				objList.addAll(invoke2);
			}
			List<ParamBean> afreshList = new ArrayList<ParamBean>();
			//执行orderPolicy.object顺序
			for(ParamBean paramBean : paramBeanList){
				
				orderPolicyObj(objList, prevValueMap, obj, paramBean);
				Method method = paramBean.getBean().getClass().getMethod("getIsAfreshExecute", null);
				Object invoke = method.invoke(paramBean.getBean());
				if((Boolean)invoke){
					afreshList.add(paramBean);
				}else{
					
					Method method5 = paramBean.getBean().getClass().getMethod("getInsertList");
					List<CaseInsensitiveMap> invoke2 = (List<CaseInsensitiveMap>)method5.invoke(paramBean.getBean());
					objList.addAll(invoke2);
				}
			}
			while (afreshList.size() > 0) {
				List<ParamBean> localAfreshList = new ArrayList<ParamBean>();
				for(ParamBean paramBean : afreshList){
					
					Method method1 = paramBean.getBean().getClass().getMethod("stopAfreshExecute", null);
					method1.invoke(paramBean.getBean());
					orderPolicyObj(objList, prevValueMap, obj, paramBean);
					Method method = paramBean.getBean().getClass().getMethod("getIsAfreshExecute", null);
					Object invoke = method.invoke(paramBean.getBean());
					if((Boolean)invoke){
						localAfreshList.add(paramBean);
					}else{
						
						Method method5 = paramBean.getBean().getClass().getMethod("getInsertList");
						List<CaseInsensitiveMap> invoke2 = (List<CaseInsensitiveMap>)method5.invoke(paramBean.getBean());
						objList.addAll(invoke2);
					}
				}
				afreshList = localAfreshList;
			}
			if (list.size() > 0) {
				for (String col : list) {
					String targetName = (String) obj.get(col);
					obj.put(col, obj.get(targetName));
				}
			}
			obj.put("dbName", columns.get(0).getTableSchema());
			obj.put("tableName", columns.get(0).getTableName());
			objList.add(obj);
			
			
		}
		
		
		return objList;
	}

	private static void orderPolicyObj(List<CaseInsensitiveMap> objList, Map<String, Object> prevValueMap,
			Map<String, Object> obj, ParamBean paramBean)
			throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
		if (prevValueMap.containsKey(paramBean.getColumn().getColumnName())) {
			Method method2 = paramBean.getBean().getClass().getMethod("setPrevValue", Object.class);
			method2.invoke(paramBean.getBean(), prevValueMap.get(paramBean.getColumn().getColumnName()));
		}
		//存入当前columns
		Method method2 = paramBean.getBean().getClass().getMethod("setCurrColumns", Columns.class);
		method2.invoke(paramBean.getBean(), paramBean.getColumn());
		
		//存入上面生成的数据对象
		Method method3 = paramBean.getBean().getClass().getMethod("setCurrObj", Map.class);
		method3.invoke(paramBean.getBean(), obj);
		
		//存入所有上面已生成的数据对象
		Method method4 = paramBean.getBean().getClass().getMethod("setAllInsertList", List.class);
		method4.invoke(paramBean.getBean(), objList);
		
		//执行执行器方法
		Object invoke = paramBean.getMethod().invoke(paramBean.getBean(), paramBean.getParam());
		obj.put(paramBean.getColumn().getColumnName(), invoke);
		
		//缓存setPrevValue的value
		prevValueMap.put(paramBean.getColumn().getColumnName(), invoke);
		obj.put(paramBean.getColumn().getColumnName(), invoke);
	}

	//设置重新执行
	public void afreshExecute() {
		
		this.isAfreshExecute = true;
		this.afreshExecuteCount++;
	}
	//停止重新执行
	public void stopAfreshExecute(){
		this.isAfreshExecute = false;
	}


	public Boolean getIsAfreshExecute() throws Exception {
		
		if(this.afreshExecuteCount >= 100){
			throw new Exception("执行次数超过100次，可能存在死循环！");
		}
		return isAfreshExecute;
	}

	public List<CaseInsensitiveMap> getAllInsertList() {
		return allInsertList;
	}




	public void setAllInsertList(List<CaseInsensitiveMap> allInsertList) {
		this.allInsertList = allInsertList;
	}




	public Map<String, Object> getCurrObj() {
		return currObj;
	}


	public void setCurrObj(Map<String, Object> currObj) {
		this.currObj = currObj;
	}


	public int getCurrIndex() {
		return currIndex;
	}


	public void setCurrIndex(int currIndex) {
		this.currIndex = currIndex;
	}


	


	public List<CaseInsensitiveMap> getInsertList() {
		return insertList;
	}

	public void setInsertList(List<CaseInsensitiveMap> insertList) {
		this.insertList = insertList;
	}

	public Columns getCurrColumns() {
		return currColumns;
	}


	public void setCurrColumns(Columns currColumns) {
		this.currColumns = currColumns;
	}


	public Object getPrevValue() {
		return prevValue;
	}

	public void setPrevValue(Object prevValue) {
		this.prevValue = prevValue;
	}

}
